package com.example.lettucedemo.controlls;

import io.lettuce.core.AbstractRedisClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author liu-rui
 * @date 2020/6/12 下午6:12
 * @description
 * @since
 */
@RestController
@Slf4j
public class MyController {
    @Autowired
    RedisTemplate<String, String> redisTemplate;

    @PostConstruct
    private void init() throws NoSuchFieldException {

        final Field connectionProviderField = LettuceConnectionFactory.class.getDeclaredField("connectionProvider");
        connectionProviderField.setAccessible(true);

        final Field channelsField = AbstractRedisClient.class.getDeclaredField("channels");
        channelsField.setAccessible(true);


        ScheduledExecutorService service = new ScheduledThreadPoolExecutor(1);

        service.scheduleWithFixedDelay(() -> {
            System.out.println("\n------------------");

            final LettuceConnectionFactory connectionFactory = (LettuceConnectionFactory) redisTemplate.getConnectionFactory();
            try {
                Object connectionProvider = connectionProviderField.get(connectionFactory);
                Field poolsField = connectionProvider.getClass().getDeclaredField("pools");
                poolsField.setAccessible(true);
                ConcurrentMap pools = (ConcurrentMap) poolsField.get(connectionProvider);

                if (CollectionUtils.isEmpty(pools)) {
                    return;
                }

                GenericObjectPool<Object> pool = (GenericObjectPool<Object>) pools.values().iterator().next();
//                log.error("create:{} destroy:{}" ,
//                        pool.getCreatedCount(),
//                        pool.getDestroyedCount());
////
//
                Field objectsField = GenericObjectPool.class.getDeclaredField("allObjects");
                objectsField.setAccessible(true);
                ConcurrentMap objects = (ConcurrentMap) objectsField.get(pool);

                if (!CollectionUtils.isEmpty(objects)) {
                    int i = 1;

                    for (Object value : objects.values()) {
                        final DefaultPooledObject pooledObject = (DefaultPooledObject) value;
                        System.out.println((i++) + " " + Integer.toHexString(value.hashCode()) + " " + pooledObject.getBorrowedCount() + " " + pooledObject.getState());
                    }
                }

            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }

        }, 10, 2, TimeUnit.SECONDS);
    }

    @GetMapping(path = "/")
    public String get() {
        return redisTemplate.opsForValue().get("a");
    }
}
